/**
 * @file list-item
 * @author liaoxuezhi@baidu.com
 */
/* eslint fecs-indent: [0, "space", 2, 2] */

import * as React from 'react';
import {
  PureComponent,
  PropTypes
} from 'react';
import Html from '../../../widgets/html.jsx';
import {Renderer, render, filter, renderChildren} from '../../renderer';
import * as cx from 'classnames';
import * as assign from 'object-assign';
import '../../action';
import {findDOMNode} from 'react-dom';
import { DragSource, DropTarget } from 'react-dnd';
import {resolveVariable} from '../../util';
const CARD_TYPE = 'row';
@Renderer({
  name: 'list-item',
  desc: '...',
  test: /(?:^|\/)list\/list-item$/
})
export default class ListItem extends PureComponent {
  static propTypes = {
    className: PropTypes.string,
    title: PropTypes.string,
    subTitle: PropTypes.string,
    desc: PropTypes.string,
    avatar: PropTypes.string,
    highlight: PropTypes.string,
    actions: PropTypes.arrayOf(PropTypes.shape({
      actionType: PropTypes.oneOf(['ajax', 'dialog', 'url', 'link']).isRequired
    })),
    onRequestAction: PropTypes.func.isRequired
  };

  static defaultProps = {
    className: 'list-group-item clearfix',
  };

  constructor(props) {
    super(props);

    this.state = {
      buildTitle: filter(props.title),
      buildSubTitle: filter(props.subTitle),
      buildDesc: filter(props.desc),
      buildAvatar: filter(props.avatar),
      buildHighlight: filter(props.highlight),
    };
  }

  componentWillReceiveProps(nextProps) {
    const props = this.props;

    if (props.item !== nextProps.item) {
      this.setState({
        buildTitle: nextProps.title !== props.title ? filter(nextProps.title) : this.state.buildTitle,
        buildSubTitle: nextProps.subTitle !== props.subTitle ? filter(nextProps.subTitle) : this.state.buildSubTitle,
        buildDesc: nextProps.desc !== props.desc ? filter(nextProps.desc) : this.state.buildDesc,
        buildAvatar: nextProps.avatar !== props.avatar ? filter(nextProps.avatar) : this.state.buildAvatar,
        buildHighlight: nextProps.highlight !== props.highlight ? filter(nextProps.highlight) : this.state.buildHighlight,
      })
    }
  }

  renderActions() {
    const {actions, onRequestAction, item, $path} = this.props;

    if (!actions) return null;

    return (
      <div
        className="pull-right btn-operation"
      >
        {actions.map((action, key) => render(`${$path}/action`, action, {
          key,
          item,
          onRequestAction,
          detectPropName: 'item'
        }))}
      </div>
    )
  }

  renderLeftActions(){
    const {onCheck, item, bulkActions, disabled, dragging, draggable, locals, $path} = this.props;
    return (
      <div className="pull-left m-r-sm">
        {
          !dragging && bulkActions && bulkActions.length && render(`${$path}/field/checkbox`, {}, {
            item,
            onCheck,
            disabled,
            locals
          })
        }
        {
          draggable && dragging && (<i className="fa fa-bars" />)
        }

      </div>
    )


  }

  renderBody() {
    const {item, bodyClassName, loading,data, locals, $path, onNotify} = this.props;
    let body = this.props.body;
    if (!body) return null;

    const dragging = this.props.stateDragging;

    if (typeof body === 'string') {
      return renderChildren(this.props.$path, body, {
        data,
        sendNotify: onNotify
      }, schema => assign({}, {className: bodyClassName}, schema));
    }

    if(!Array.isArray(body)) {
      body = [body];
    }
    let element = body.map((field, key) => {

      if(Array.isArray(field)) {
        return (
          <div key={key} className="hbox">
            {
              field.map((field, key)=> {
                return (
                  <div className="col" key={key}>
                    {
                      render(`${$path}/field`, assign({
                        type: 'text'
                      }, field), {
                        key,
                        item: item,
                        data: assign({
                        }, data, item),
                        onCheck: this.props.toggle,
                        onRequestAction: this.props.onRequestAction,
                        onFieldValueChange: this.props.onFieldValueChange,
                        onFieldValueSave: this.props.onFieldValueSave,
                        value: resolveVariable(field.name, item),
                        disabled: loading,
                        disableQuickEdit: dragging || loading,
                        locals,
                        onNotify
                      })
                    }
                  </div>
                )}
              )
            }
          </div>
        )
      }
      return render(`${$path}/field`, assign({
        type: 'text'
      }, field), {
        key,
        item: item,
        data: assign({
        }, data, item),
        onCheck: this.props.toggle,
        onRequestAction: this.props.onRequestAction,
        onFieldValueChange: this.props.onFieldValueChange,
        onFieldValueSave: this.props.onFieldValueSave,
        value: item[field.name],
        disabled: loading,
        disableQuickEdit: dragging || loading,
        locals
      })
    });

    return (
      <div className={cx(bodyClassName)}>
        {element}
      </div>
    )
  }

  render() {
    const {
      className,
      item,
      draggable,
      dragging
    } = this.props;

    const {
      buildTitle,
      buildSubTitle,
      buildDesc,
      buildAvatar,
      buildHighlight
    } = this.state;

    const avatar = buildAvatar && buildAvatar(item);
    return (draggable && dragging)? (
      <DraggableLi
        className={cx("list-group-item clearfix", className)}
        id={item.$id}
        findRow={this.props.findRow}
        moveRow={this.props.moveRow}
        moveRowConfirm={this.props.moveRowConfirm}
      >
        {this.renderLeftActions()}
        {this.renderActions()}
        {avatar ? (
          <span className="pull-left thumb-sm avatar m-r">
            <img src={avatar} alt="..." />
            {buildHighlight && buildHighlight(item) ? (<i className="busy b-white bottom" />) : null}
          </span>
        ) : null}
        <div className="clear">
          {buildTitle ? (<span>{buildTitle(item)}</span>) : null}
          {buildSubTitle ? (<small className="text-muted clear text-ellipsis">{buildSubTitle(item)}</small>) : null}
          {buildDesc ? (<Html html={buildDesc(item)} />) : null}
          {
            this.renderBody()
          }
        </div>

      </DraggableLi>
    ):(
      <li className={cx("list-group-item clearfix", className)}>
        {this.renderLeftActions()}
        {this.renderActions()}
        {avatar ? (
          <span className="pull-left thumb-sm avatar m-r">
            <img src={avatar} alt="..." />
            {buildHighlight && buildHighlight(item) ? (<i className="busy b-white bottom" />) : null}
          </span>
        ) : null}
        <div className="clear">
          {buildTitle ? (<span>{buildTitle(item)}</span>) : null}
          {buildSubTitle ? (<small className="text-muted clear text-ellipsis">{buildSubTitle(item)}</small>) : null}
          {buildDesc ? (<Html html={buildDesc(item)} />) : null}
          {
            this.renderBody()
          }
        </div>
      </li>
    );
  }
}

/**
 * 让 li 可拖拽
 */
const cardTarget = {
  canDrop() {
    return true;
  },

  hover(props, monitor, component) {
    const { id: draggedId, originalIndex: dragIndex} = monitor.getItem();
    const { id: overId } = props;

    if (draggedId !== overId) {
      const { index: overIndex } = props.findRow(overId);

      const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();
      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
      const clientOffset = monitor.getClientOffset();
      const hoverClientY = clientOffset.y - hoverBoundingRect.top;

      // Dragging downwards
      if (dragIndex < overIndex && hoverClientY < hoverMiddleY) {
        return;
      }

      // Dragging upwards
      if (dragIndex > overIndex && hoverClientY > hoverMiddleY) {
        return;
      }

      props.moveRow(draggedId, overIndex);
    }
  }
};
const cardSource = {
  beginDrag(props, monitor, component) {
    return {
      id: props.id,
      originalIndex: props.findRow(props.id).index
    };
  },

  endDrag(props, monitor, component) {
    const { id: droppedId, originalIndex } = monitor.getItem();
    const didDrop = monitor.didDrop();

    if (didDrop) {
      props.moveRowConfirm(droppedId);
    } else {
      props.moveRow(droppedId, originalIndex);
    }
  }
};
@DropTarget(CARD_TYPE, cardTarget, connect => ({
  connectDropTarget: connect.dropTarget()
}))
@DragSource(CARD_TYPE, cardSource, (connect, monitor) => ({
  connectDragSource: connect.dragSource(),
  connectDragPreview: connect.dragPreview(),
  isDragging: monitor.isDragging()
}))
class DraggableLi extends PureComponent {
  static propTypes = {
    connectDragSource: PropTypes.func.isRequired,
    connectDragPreview: PropTypes.func.isRequired,
    connectDropTarget: PropTypes.func.isRequired,
    id: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.string
    ]).isRequired,
    isDragging: PropTypes.bool.isRequired,
    findRow: PropTypes.func.isRequired,
    moveRow: PropTypes.func.isRequired,
    moveRowConfirm: PropTypes.func.isRequired
  };
  componentDidMount() {
    const {connectDragSource} = this.props;
    let dom = findDOMNode(this);
    connectDragSource(dom);
  }
  render() {
    const {
      isDragging,
      connectDragPreview,
      connectDropTarget,
      className
    } = this.props;

    // console.log('Re render');

    return connectDropTarget(connectDragPreview(
      <li
        className={cx(className,'draggable', {
          'li-dragging': isDragging
        })}
      >
        {this.props.children}
      </li>
    ));
  }
}
